package com.bwie.service.impl;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import com.bwie.common.constants.Constants;
import com.bwie.common.constants.JwtConstants;
import com.bwie.common.constants.TokenConstants;
import com.bwie.common.domain.Role;
import com.bwie.common.domain.User;
import com.bwie.common.domain.response.UserLoginRes;
import com.bwie.common.exceptions.BizExceptions;
import com.bwie.common.result.Result;
import com.bwie.common.utils.ImageVerificationCode;
import com.bwie.common.utils.JwtUtils;
import com.bwie.remote.UserRemote;
import com.bwie.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @className: UserServiceImpl
 * @Description: TODO
 * @version: v1.８.0
 * @author: 汪菲阳
 * @date: 2025/10/22 9:32
 */
@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private UserRemote userRemote;
    @Autowired
    private BCryptPasswordEncoder bCryptPasswordEncoder;
    @Autowired
    private HttpServletRequest request;

    /**
     * 锁定时间
     */
    private static final Integer MAX_LOCK_TIME=5;
    /**
     * 重试次数
     */
    private static final Integer MAX_COUNT=3;

    @Override
    public void getImageCode(OutputStream outputStream) {
        //获取工具类
        ImageVerificationCode imageVerificationCode = new ImageVerificationCode();
        ///获取图片
        BufferedImage image = imageVerificationCode.getImage();
        //获取文本验证码
        String text = imageVerificationCode.getText();
        //存入redis
        redisTemplate.opsForValue().set("imgCode",text,5,TimeUnit.MINUTES);
        //将图片返回页面
        try {
            imageVerificationCode.output(image,outputStream);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void sendCode(String userPhone) {
        //判断redis中是否存在验证码
        Boolean redisCode = redisTemplate.hasKey(userPhone + TokenConstants.CODE);
        //判断
        if (redisCode){
            throw new BizExceptions(Constants.SEND_CODE_EXITES_CODE,Constants.SEND_CODE_EXITES_MSG);
        }
        //生成验证码
        String code = RandomUtil.randomNumbers(4);
        //存入redis
        redisTemplate.opsForValue().set(userPhone+TokenConstants.CODE,code,5, TimeUnit.MINUTES);
    }

    @Override
    public UserLoginRes login(User user) {
        //卫语句
        String userPhone = user.getUserPhone();
        //获取用户输入的验证码
        String code = user.getCode();
        //获取用户输入的密码
        String userPassword = user.getUserPassword();
        //获取用户id
        Integer userId = user.getUserId();
        //获取锁
        Boolean redisLock = redisTemplate.hasKey(TokenConstants.USER_LOCK + userId);
        //判断锁是否已经存在，存在则抛异常
        if (redisLock){
            throw new BizExceptions(Constants.LOGIN_LOCK_EXITS_CODE,Constants.LOGIN_LOCK_EXITS_MSG);
        }
        User userInfo = getUserInfo(user);
        //非空,如果为空则进行注册用户
        if (userInfo==null){
            //注册用户
            Result result = userRemote.registerUser(user);
            //熔断
            if (result.getCode()==Constants.ERROR){
                throw new BizExceptions(Constants.REGISTER_USER_ERROR_CODE,Constants.REGISTER_USER_ERROR_MSG);
            }
        }
        //获取redis中的验证码
        String redisCode = (String) redisTemplate.opsForValue().get(userPhone + TokenConstants.CODE);
        //获取mysql中的密码
        String mysqlUserPassword = userInfo.getUserPassword();
        //判断密码或者验证码是否正确
        if (redisCode.equals(code) || bCryptPasswordEncoder.matches(mysqlUserPassword,userPassword)){
            //密码错误则自增错误次数
            Long incrementCount = redisTemplate.opsForValue().increment(TokenConstants.USER_ERROR_COUNT + userId);
            //锁定时间
            redisTemplate.expire(TokenConstants.USER_LOCK+userId,MAX_LOCK_TIME,TimeUnit.MINUTES);
            //判断如果重试次数大于最大重试次数则锁定
            if (incrementCount > MAX_COUNT){
                //添加锁
                redisTemplate.opsForValue().set(TokenConstants.USER_LOCK+userId,true);
                //添加锁定时间
                redisTemplate.expire(TokenConstants.USER_LOCK+userId,MAX_LOCK_TIME,TimeUnit.MINUTES);
                //释放锁
                redisTemplate.delete(TokenConstants.USER_LOCK+userId);
            }
            throw new BizExceptions(Constants.LOGIN_PSSWORD_OR_CODE_ERROR_CODE,Constants.LOGIN_PSSWORD_OR_CODE_ERROR_MSG);
        }

        //生成token
        HashMap<String, Object> map = new HashMap<>();
        //获取userKey
        String userKey = IdUtil.fastSimpleUUID();
        //将userKey放进map中
        map.put(JwtConstants.USER_KEY,userKey);
        String token = JwtUtils.createToken(map);
        //获取返回对象
        UserLoginRes userLoginRes = new UserLoginRes();
        //给token赋值
        userLoginRes.setToken(token);
        //获取角色信息
        List<Role> roleList = getRoleList(userId);
        //赋值
        userLoginRes.setRoleList(roleList);
        //将角色信息存入redis
        redisTemplate.opsForValue().set(TokenConstants.ROLE_INFO+userKey,roleList);
        return userLoginRes;
    }

    @Override
    public void redisImgCode(String imgCode) {
        //获取token
        String token = request.getHeader(TokenConstants.TOKEN);
        //非空
        if (token == null){
            throw new BizExceptions(Constants.LOGIN_NULL_CODE,Constants.LOGIN_NULL_MSG);
        }
        //判断图片验证码是否存在
        Boolean b = redisTemplate.hasKey("imgCode");
        if (!b){
            throw new BizExceptions(Constants.IMG_CODE_NULL_CODE,Constants.IMG_CODE_NULL_MAG);
        }
        //获取图文验证码
        String redisCode = (String) redisTemplate.opsForValue().get("imgCode");
        //判断图片验证码是否正确
        if (!redisCode.equals(imgCode)){
            throw new BizExceptions(Constants.IMG_CODE_ERROR_CODE,Constants.IMG_CODE_ERROR_MAG);
        }
    }

    @Override
    public void saleRole(Integer roleId) {
        //获取token
        String token = request.getHeader(TokenConstants.TOKEN);
        //非空
        if (token == null){
            throw new BizExceptions(Constants.LOGIN_NULL_CODE,Constants.LOGIN_NULL_MSG);
        }
        //获取userKey
        String userKey = JwtUtils.getUserKey(token);
        //将角色id存入redis
        redisTemplate.opsForValue().set(TokenConstants.ROLE_ID+userKey,roleId,30,TimeUnit.MINUTES);
    }

    /**
     * 远程查询角色
     * @param userId
     * @return
     */
    private List<Role> getRoleList(Integer userId){
        //获取角色信息
        Result<List<Role>> listResult = userRemote.selectRoleByUserId(userId);
        //熔断
        if (listResult.getCode()==Constants.ERROR){
            throw new BizExceptions(Constants.LOGIN_ROLE_ERROR_CODE,Constants.LOGIN_ROLE_ERROR_MSG);
        }
        //获取数据
        List<Role> roleList = listResult.getData();
        //非空
        if (roleList==null){
            throw new BizExceptions(Constants.LOGIN_ROLE_NULL_CODE,Constants.LOGIN_ROLE_NULL_MSG);
        }
        return roleList;
    }

    /**
     * 远程查询用户
     * @param user
     * @return
     */
    private User getUserInfo(User user){
        //判断手机号是否存在
        Result<User> userResult = userRemote.selectUserByUserPhoneOrName(user);
        //熔断
        if (userResult.getCode()== Constants.ERROR){
            throw new BizExceptions(Constants.SEND_CODE_ERROR_CODE,Constants.SNED_CODE_ERROR_MAG);
        }
        //获取数据
        User loginData = userResult.getData();
        return loginData;
    }
}
